﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Security.Cryptography;
using System.IO;
using System.Collections;

namespace Reviewer {
    /// <summary>
    /// 
    /// </summary>
    public class HGNXHelper {
        MatchCollection mc;
        int[,] pieces = new int[26, 2];     // 棋子数组

        //public bool VerifyFileExtension(string file) {
        //    return file.EndsWith("hgnx", true, new CultureInfo("en-US"));
        //}

        /// <summary>
        /// 验证HGN文件的完整性。
        /// </summary>
        /// <param name="hgnx">加密的HGN文件内容</param>
        /// <returns></returns>
        public bool VerifyHGNX(string hgnx) {
            if (hgnx.Length < 32) {
                return false;
            }
            string code = hgnx.Substring(0, 32);
            MD5 md5 = MD5.Create();
            byte[] bytes = md5.ComputeHash(Encoding.Default.GetBytes(hgnx.Substring(32)));

            return BitConverter.ToString(bytes).Replace("-", "") == code;
        }

        //public string GetHGNID(string hgn) {
        //    return hgn.Substring(0, hgn.IndexOf(" "));
        //}

        /// <summary>
        /// 转换SGF文件为标准坐标系下的未加密的HGNX字符串。
        /// </summary>
        /// <param name="fileName">SGF文件的绝对地址</param>
        /// <param name="rotate">转换到标准坐标系需要旋转的角度。</param>
        /// <param name="flip">转换到标准坐标系需要翻转的方向。</param>
        /// <returns></returns>
        private string BuildHGNXFromSGFFile(string fileName, string rotate, string flip) {
            string hgnx = "";
            StreamReader reader = new StreamReader(fileName);
            hgnx = reader.ReadToEnd();
            reader.Close();

            InitPieces();
            string _source = hgnx.Replace("\r", "");
            string _pattern = "P.\\[.{1,3} dropb (.{1,2}) [A-Z] \\d{1,2} (.*)]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} move [A-Z] (.{1,2}) [A-Z] \\d{1,2} (.*)]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} pass]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} done]";
            mc = Regex.Matches(_source, _pattern, RegexOptions.IgnoreCase);

            GetGameInfo(_source, fileName);

            string moves = "";
            for (int i = 0; i < mc.Count; i++) {
                if (mc[i].Groups[1].Value != "") {
                    int index = GetPieceIndex(mc[i].Groups[1].Value, i);
                    if (index != -1) {
                        moves += (index + "," + FlipMove(BuildMove(index, mc[i].Groups[2].Value, rotate), flip)) + " ";
                    }
                } else if (mc[i].Groups[3].Value != "") {
                    int index = GetPieceIndex(mc[i].Groups[3].Value, i);
                    if (index != -1) {
                        moves += (index + "," + FlipMove(BuildMove(index, mc[i].Groups[4].Value, rotate), flip)) + " ";
                    }
                }
            }

            _result = CalculateResult(_source);
            hgnx = _id + " " + _type + " " + _wp + " " + _bp + " " + _result + " " + _wt + " " + _bt + " " + moves;
            hgnx = hgnx.TrimEnd();

            return hgnx;
        }

        /// <summary>
        /// 根据指定翻转方向翻转给定的走法。
        /// </summary>
        /// <param name="move">走法字符串。</param>
        /// <param name="type">翻转的方向。</param>
        /// <returns></returns>
        private string FlipMove(string move, string type) {
            string[] ar = move.Split(',');
            int x, y;
            switch (type) {
                case "H":
                    x = Int32.Parse(ar[0]);
                    if (x != -999) { ar[0] = (-x).ToString(); }
                    x = Int32.Parse(ar[2]);
                    if (x != -999) { ar[2] = (-x).ToString(); }
                    break;
                case "V":
                    y = Int32.Parse(ar[1]);
                    if (y != -999) { ar[1] = (-y).ToString(); }
                    y = Int32.Parse(ar[3]);
                    if (y != -999) { ar[3] = (-y).ToString(); }
                    break;
                case "HV":
                    x = Int32.Parse(ar[0]);
                    if (x != -999) { ar[0] = (-x).ToString(); }
                    x = Int32.Parse(ar[2]);
                    if (x != -999) { ar[2] = (-x).ToString(); }
                    y = Int32.Parse(ar[1]);
                    if (y != -999) { ar[1] = (-y).ToString(); }
                    y = Int32.Parse(ar[3]);
                    if (y != -999) { ar[3] = (-y).ToString(); }
                    break;
            }

            return ar[0] + "," + ar[1] + "," + ar[2] + "," + ar[3];
        }

        private string _type = "";
        private string _wp = "";
        private string _bp = "";
        private string _wt = "";
        private string _bt = "";
        private string _id = "";
        private string _result = "";

        /// <summary>
        /// 获取SGF文件的对局信息。
        /// </summary>
        /// <param name="sgf">SGF文件内容。</param>
        /// <param name="fileName">SGF文件绝对路径。</param>
        private void GetGameInfo(string sgf, string fileName) {
            string pattern = "SU\\[(.*)]";
            Match m = Regex.Match(sgf, pattern);
            _type = m.Groups[1].Value;
            pattern = "P.\\[id \"(.*)\"]";
            MatchCollection tmp = Regex.Matches(sgf, pattern, RegexOptions.IgnoreCase);
            _wp = tmp[0].Groups[1].Value;
            _bp = tmp[1].Groups[1].Value;
            pattern = "P.\\[time (.*) ]";
            tmp = Regex.Matches(sgf, pattern, RegexOptions.IgnoreCase);
            _wt = tmp[0].Groups[1].Value;
            _bt = tmp[1].Groups[1].Value;
            pattern = "GC\\[(.*)]";
            m = Regex.Match(sgf, pattern);
            _id = fileName.Substring(fileName.LastIndexOf("\\") + 1).Replace(".sgf", "");
        }

        private int WQ_X;
        private int WQ_Y;
        private int BQ_X;
        private int BQ_Y;

        /// <summary>
        /// 获取当前对局的结果
        /// </summary>
        /// <param name="sgf">SGF文件内容</param>
        /// <returns></returns>
        private string CalculateResult(string sgf) {
            // 先通过SGF查找是否有一方认输的记录。
            string pattern = "P(.)\\[\\d* resign\\]";
            Match m = Regex.Match(sgf, pattern);
            if (m.Success) {
                return (m.Groups[1].Value == "0") ? "0-1" : "1-0";
            }

            // 分析当前黑白两方蜂王的位置周围的六个位置。
            // 如果只有一方被围住，对方获胜；
            // 如果两方同时被围住，和棋。
            bool white = false;
            bool black = false;
            if (HavePieceAtPos(WQ_X + 2, WQ_Y) &&
                HavePieceAtPos(WQ_X - 2, WQ_Y) &&
                HavePieceAtPos(WQ_X - 1, WQ_Y - 1) &&
                HavePieceAtPos(WQ_X + 1, WQ_Y - 1) &&
                HavePieceAtPos(WQ_X - 1, WQ_Y + 1) &&
                HavePieceAtPos(WQ_X + 1, WQ_Y + 1)) {
                black = true;
            }
            if (HavePieceAtPos(BQ_X + 2, BQ_Y) &&
                HavePieceAtPos(BQ_X - 2, BQ_Y) &&
                HavePieceAtPos(BQ_X - 1, BQ_Y - 1) &&
                HavePieceAtPos(BQ_X + 1, BQ_Y - 1) &&
                HavePieceAtPos(BQ_X - 1, BQ_Y + 1) &&
                HavePieceAtPos(BQ_X + 1, BQ_Y + 1)) {
                white = true;
            }
            if (black && white) {
                return "1/2-1/2";
            } else {
                if (white) {
                    return "1-0";
                }
                if (black) {
                    return "0-1";
                }
            }
            return "1/2-1/2";
        }

        /// <summary>
        /// 判断指定棋盘坐标位置是否有棋子。
        /// </summary>
        /// <param name="x">棋盘坐标X。</param>
        /// <param name="y">棋盘坐标Y。</param>
        /// <returns></returns>
        private bool HavePieceAtPos(int x, int y) {
            for (int i = 0; i < 26; i++) {
                if (pieces[i, 0] == x && pieces[i, 1] == y) {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 通过棋子简写名称和下棋方获取棋子在棋子数组中的序号。
        /// </summary>
        /// <param name="name">棋子的简写名称。</param>
        /// <param name="index">下棋方。</param>
        /// <returns></returns>
        private int GetPieceIndex(string name, int side) {
            bool flag = side % 2 == 0;
            switch (name) {
                case "Q":
                    return flag ? 0 : 13;
                case "A3":
                    return flag ? 1 : 14;
                case "A2":
                    return flag ? 2 : 15;
                case "A1":
                    return flag ? 3 : 16;
                case "G3":
                    return flag ? 4 : 17;
                case "G2":
                    return flag ? 5 : 18;
                case "G1":
                    return flag ? 6 : 19;
                case "B2":
                    return flag ? 7 : 20;
                case "B1":
                    return flag ? 8 : 21;
                case "S2":
                    return flag ? 9 : 22;
                case "S1":
                    return flag ? 10 : 23;
                case "M1":
                    return flag ? 11 : 24;
                case "L1":
                    return flag ? 12 : 25;
            }
            return -1;
        }

        private string BuildMove(int index, string move, string rotate) {
            string targetPName = "";
            int targetPSide = 0;
            int targetPIndex = -1;
            int targetPX = -1;
            int targetPY = -1;
            if (move == ".") {
                return MakeMove(index, 0, 0);
            }
            if (move.StartsWith("\\")) {
                targetPName = move.Substring(3);
                targetPSide = (move.Substring(2, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] - 1;
                targetPY = pieces[targetPIndex, 1] - 1;
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] - 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] + 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.StartsWith("-")) {
                targetPName = move.Substring(2);
                targetPSide = (move.Substring(1, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] - 2;
                targetPY = pieces[targetPIndex, 1];
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.StartsWith("/")) {
                targetPName = move.Substring(2);
                targetPSide = (move.Substring(1, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] - 1;
                targetPY = pieces[targetPIndex, 1] + 1;
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] - 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] + 2;
                    targetPY = pieces[targetPIndex, 1];
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.EndsWith("/")) {
                targetPName = move.Substring(1, move.Length - 2);
                targetPSide = (move.Substring(0, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] + 1;
                targetPY = pieces[targetPIndex, 1] - 1;
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] + 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] - 2;
                    targetPY = pieces[targetPIndex, 1];
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.EndsWith("-")) {
                targetPName = move.Substring(1, move.Length - 2);
                targetPSide = (move.Substring(0, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] + 2;
                targetPY = pieces[targetPIndex, 1];
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.EndsWith("\\")) {
                targetPName = move.Substring(1, move.Length - 3);
                targetPSide = (move.Substring(0, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0] + 1;
                targetPY = pieces[targetPIndex, 1] + 1;
                if (rotate == "60") {
                    targetPX = pieces[targetPIndex, 0] - 1;
                    targetPY = pieces[targetPIndex, 1] + 1;
                } else if (rotate == "-60") {
                    targetPX = pieces[targetPIndex, 0] + 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "120") {
                    targetPX = pieces[targetPIndex, 0] - 2;
                    targetPY = pieces[targetPIndex, 1];
                } else if (rotate == "-120") {
                    targetPX = pieces[targetPIndex, 0] + 1;
                    targetPY = pieces[targetPIndex, 1] - 1;
                }
                return MakeMove(index, targetPX, targetPY);
            }
            if (move.StartsWith("w") || move.StartsWith("b")) {
                targetPName = move.Substring(1);
                targetPSide = (move.Substring(0, 1) == "w") ? 0 : 1;
                targetPIndex = GetPieceIndex(targetPName, targetPSide);
                targetPX = pieces[targetPIndex, 0];
                targetPY = pieces[targetPIndex, 1];
                return MakeMove(index, targetPX, targetPY);
            }

            return "";
        }

        /// <summary>
        /// 执行走法，更新棋子数组。
        /// </summary>
        /// <param name="index">棋子序号。</param>
        /// <param name="x">走法X坐标。</param>
        /// <param name="y">走法Y坐标。</param>
        /// <returns></returns>
        private string MakeMove(int index, int x, int y) {
            string str = pieces[index, 0] + "," + pieces[index, 1] + "," + x + "," + y;
            pieces[index, 0] = x;
            pieces[index, 1] = y;

            if (index == 0) {
                WQ_X = x;
                WQ_Y = y;
            } else if (index == 13) {
                BQ_X = x;
                BQ_Y = y;
            }

            return str;
        }

        /// <summary>
        /// 初始化棋子数组。
        /// </summary>
        private void InitPieces() {
            for (int i = 0; i < 26; i++) {
                for (int j = 0; j < 2; j++) {
                    pieces[i, j] = -999;
                }
            }
        }

        /// <summary>
        /// 读取SGF文件自动转换成标准坐标系的未加密的HGNX字符串。
        /// </summary>
        /// <param name="fileName">SGF文件绝对位置。</param>
        /// <returns></returns>
        public string BuildHGNXFromSGFFile(string fileName) {
            string hgnx = "";
            string rotate = "";
            string flip = "";

            StreamReader reader = new StreamReader(fileName);
            hgnx = reader.ReadToEnd();
            reader.Close();

            InitPieces();
            string _source = hgnx.Replace("\r", "");
            string _pattern = "P.\\[.{1,3} dropb (.{1,2}) [A-Z] \\d{1,2} (.*)]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} move [A-Z] (.{1,2}) [A-Z] \\d{1,2} (.*)]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} pass]\n.*P.\\[.{1,3} done]|P.\\[.{1,3} done]";
            mc = Regex.Matches(_source, _pattern, RegexOptions.IgnoreCase);

            if (mc.Count > 2) {
                string blackFirstMove = (mc[1].Groups[2].Value != "") ? mc[1].Groups[2].Value : mc[1].Groups[4].Value;

                bool whiteFlag = false;
                bool blackFlag = false;
                for (int i = 0; i < 8; i++) {
                    if (i >= mc.Count) {
                        break;
                    }
                    if (mc[i].Groups[1].Value != "") {
                        int index = GetPieceIndex(mc[i].Groups[1].Value, i);
                        if (index != -1) {
                            if (index == 0) {
                                if (!whiteFlag) {
                                    BuildMove(index, mc[i].Groups[2].Value, "");
                                    whiteFlag = true;
                                }
                            } else if (index == 13) {
                                if (!blackFlag) {
                                    BuildMove(index, mc[i].Groups[2].Value, "");
                                    blackFlag = true;
                                }
                            } else {
                                BuildMove(index, mc[i].Groups[2].Value, "");
                            }
                        }
                    } else if (mc[i].Groups[3].Value != "") {
                        int index = GetPieceIndex(mc[i].Groups[3].Value, i);
                        if (index != -1) {
                            if (index == 0) {
                                if (!whiteFlag) {
                                    BuildMove(index, mc[i].Groups[4].Value, "");
                                    whiteFlag = true;
                                }
                            } else if (index == 13) {
                                if (!blackFlag) {
                                    BuildMove(index, mc[i].Groups[4].Value, "");
                                    blackFlag = true;
                                }
                            } else {
                                BuildMove(index, mc[i].Groups[4].Value, "");
                            }
                        }
                    }
                }

                if (blackFirstMove.StartsWith("\\")) {
                    rotate = "120";
                    if (pieces[0, 0] > 0 && Math.Abs(pieces[0, 0]) == Math.Abs(pieces[0, 1])) {
                        if (pieces[13, 0] < 0 && pieces[13, 1] != 0 && Math.Abs(pieces[13, 0] / pieces[13, 1]) > 1) {
                            flip = "V";
                        }
                    } else if ((pieces[0, 0] <= 0 && pieces[0, 1] >= 0) ||
                        (pieces[0, 0] > 0 && pieces[0, 1] != 0 && Math.Abs(pieces[0, 0] / pieces[0, 1]) < 1)) {
                        flip = "V";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
                if (blackFirstMove.StartsWith("-")) {
                    //flip = (pieces[0, 1] < 0) ? "HV" : "H";
                    if (pieces[0, 1] == 0) {
                        flip = (pieces[13, 1] < 0) ? "HV" : "H";
                    } else {
                        flip = (pieces[0, 1] < 0) ? "HV" : "H";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
                if (blackFirstMove.StartsWith("/")) {
                    rotate = "-120";
                    if (pieces[0, 0] > 0 && Math.Abs(pieces[0, 0]) == Math.Abs(pieces[0, 1])) {
                        if ((pieces[13, 0] >= 0 && pieces[13, 1] >= 0) ||
                            (pieces[13, 0] < 0 && pieces[13, 1] != 0 && Math.Abs(pieces[13, 0] / pieces[13, 1]) < 1)) {
                            flip = "V";
                        }
                    } else if ((pieces[0, 0] >= 0 && pieces[0, 1] >= 0) ||
                       (pieces[0, 0] > 0 && pieces[0, 1] != 0 && Math.Abs(pieces[0, 0] / pieces[0, 1]) > 1)) {
                        flip = "V";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
                if (blackFirstMove.EndsWith("/")) {
                    rotate = "60";
                    if (pieces[0, 0] < 0 && Math.Abs(pieces[0, 0]) == Math.Abs(pieces[0, 1])) {
                        if ((pieces[13, 0] <= 0 && pieces[13, 1] <= 0) ||
                            (pieces[13, 0] > 0 && pieces[13, 1] != 0 && Math.Abs(pieces[13, 0] / pieces[13, 1]) < 1)) {
                            flip = "V";
                        }
                    } else if ((pieces[0, 0] <= 0 && pieces[0, 1] <= 0) ||
                       (pieces[0, 0] < 0 && pieces[0, 1] != 0 && Math.Abs(pieces[0, 0] / pieces[0, 1]) > 1)) {
                        flip = "V";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
                if (blackFirstMove.EndsWith("-")) {
                    rotate = "";
                    //flip = (pieces[0, 1] < 0) ? "V" : "";
                    if (pieces[0, 1] == 0) {
                        flip = (pieces[13, 1] < 0) ? "V" : "";
                    } else {
                        flip = (pieces[0, 1] < 0) ? "V" : "";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
                if (blackFirstMove.EndsWith("\\")) {
                    rotate = "-60";
                    if (pieces[0, 0] < 0 && Math.Abs(pieces[0, 0]) == Math.Abs(pieces[0, 1])) {
                        if ((pieces[13, 0] <= 0 && pieces[13, 1] <= 0) ||
                            (pieces[13, 0] > 0 && pieces[13, 1] != 0 && Math.Abs(pieces[13, 0] / pieces[13, 1]) < 1)) {
                            flip = "V";
                        }
                    } else if ((pieces[0, 0] >= 0 && pieces[0, 1] <= 0) ||
                        pieces[0, 0] < 0 && pieces[0, 1] != 0 && Math.Abs(pieces[0, 0] / pieces[0, 1]) < 1) {
                        flip = "V";
                    }
                    hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                    return hgnx;
                }
            } else {
                hgnx = BuildHGNXFromSGFFile(fileName, rotate, flip);
                return hgnx;
            }
            return "";
        }

        /// <summary>
        /// 读取SGF文件转换成标准坐标系的未加密HGNX字符串，并在载入到主窗体中。
        /// </summary>
        /// <param name="frmMain">主窗体。</param>
        /// <param name="fileName">SGF文件绝对位置。</param>
        public void ReadSGFFile(FrmMain frmMain, string fileName) {
            string hgnx = BuildHGNXFromSGFFile(fileName);
            frmMain.LoadDecodedHGNX(hgnx);
        }

        /// <summary>
        /// 读取HGN文件并在载入到主窗体中。
        /// </summary>
        /// <param name="frmMain">主窗体。</param>
        /// <param name="fileName">HGN文件绝对位置。</param>
        public void ReadHGNFile(FrmMain frmMain, string fileName) {
            string hgn;
            StreamReader sr = new StreamReader(fileName);
            hgn = sr.ReadLine();
            sr.Close();
            if (VerifyHGNX(hgn)) {
                hgn = Encoding.Default.GetString(Convert.FromBase64String(hgn.Substring(32)));
                frmMain.LoadDecodedHGNX(hgn);
            }
        }
    }
}
